home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / muds / lpmud312.tar / lpmud312 / parse.c < prev    next >
C/C++ Source or Header  |  1992-01-06  |  48KB  |  1,915 lines

  1. /*
  2.  
  3.   Pattern Parser package for LPmud, JnA 1991
  4.  
  5.   Ver 3.1
  6.  
  7.   If you have questions or complaints about this code please refer them
  8.   to jna@cd.chalmers.se
  9.  
  10. */
  11.  
  12. #include <stdio.h>
  13. #include <string.h>
  14. #include <ctype.h>
  15. #include <time.h>
  16. #include "lint.h"
  17. #include "interpret.h"
  18. #include "config.h"
  19. #include "object.h"
  20. #include "wiz_list.h"
  21.  
  22. extern char *string_copy PROT((char *)), *xalloc PROT((int));
  23. extern int d_flag; /* for debugging purposes */
  24. extern struct object *previous_ob;
  25.  
  26. #ifndef tolower            /* On some systems this is a function */
  27. extern int tolower PROT((int));
  28. #endif
  29.  
  30. #ifndef COMPAT_MODE
  31. /*****************************************************
  32.  
  33.   This is the parser used by the efun parse_command
  34.  
  35. */
  36. /*
  37.  
  38.   General documentation:
  39.  
  40.   parse_command() is one of the most complex efun in LPmud to use. It takes
  41.   some effort to learn and use, but when mastered, very powerfull constructs
  42.   can be implemented.
  43.  
  44.   Basically parse_command() is a piffed up sscanf operating on word basis. It
  45.   works similar to sscanf in that it takes a pattern and a variable set of
  46.   destination arguments. It is together with sscanf the only efun to use
  47.   pass by reference for other variables than arrays.
  48.  
  49.   To make the efun usefull it must have a certain support from the mudlib,
  50.   there is a set of functions that it needs to call to get relevant
  51.   information before it can parse in a sensible manner.
  52.  
  53.   In earlier versions it used the normal id() lfun in the LPC objects to
  54.   find out if a given object was identified by a certain string. This was
  55.   highly inefficient as it could result in hundreds or maybe thousands of
  56.   calls when very long commands were parsed. 
  57.   
  58.   The new version relies on the LPC objects to give it three lists of 'names'.
  59.  
  60.        1 - The normal singular names.
  61.        2 - The plural forms of the names.
  62.        3 - The acknowledged adjectives of the object.
  63.  
  64.   These are fetched by calls to the functions:
  65.  
  66.        1 - string *parse_command_id_list();
  67.        2 - string *parse_command_plural_id_list();
  68.        3 - string *parse_command_adjectiv_id_list();
  69.  
  70.   The only really needed list is the first. If the second does not exist
  71.   than the efun will try to create one from the singluar list. For 
  72.   grammatical reasons it does not always succeed in a perfect way. This is
  73.   especially true when the 'names' are not single words but phrases.
  74.  
  75.   The third is very nice to have because it makes constructs like
  76.   'get all the little blue ones' possible.
  77.  
  78.   Apart from these functions that should exist in all objects, and which
  79.   are therefore best put in /std/object.c there is also a set of functions
  80.   needed in /secure/master.c These are not absolutely necessary but they
  81.   give extra power to the efun.
  82.  
  83.   Basically these /secure/master.c lfuns are there to give default values
  84.   for the lists of names fetched from each object.
  85.  
  86.   The names in these lists are applicable to any and all objects, the first
  87.   three are identical to the lfun's in the objects:
  88.  
  89.        string *parse_command_id_list()
  90.                 - Would normally return: ({ "one", "thing" })
  91.  
  92.        string *parse_command_plural_id_list()
  93.                 - Would normally return: ({ "ones", "things", "them" })
  94.  
  95.        string *parse_command_adjectiv_id_list()
  96.                 - Would normally return ({ "iffish" })
  97.  
  98.   The last two are the default list of the prepositions and a single so called
  99.   'all' word. 
  100.  
  101.        string *parse_command_prepos_list()
  102.                  - Would normally return: ({ "in", "on", "under" })
  103.  
  104.        string parse_command_all_word()
  105.                  - Would normally return: "all"
  106.  
  107.   IF you want to use a different language than English but still want the
  108.   default pluralform maker to work, you need to replace parse.c with the
  109.   following file:
  110.  
  111. #if 0
  112.     * Language configured parse.c
  113.     *
  114.     #define PARSE_FOREIGN
  115.    
  116.     char *parse_to_plural(str)
  117.         char *str;
  118.     {
  119.  
  120.         * Your own plural converter for your language *
  121.      
  122.     }
  123.  
  124.       * The numberwords below should be replaced for the new language *
  125.  
  126.     static char *ord1[] = {"", "first", "second", "third", "fourth", "fifth",
  127.                "sixth", "seventh", "eighth", "nineth", "tenth",
  128.                "eleventh", "twelfth", "thirteenth", "fourteenth",
  129.                "fifteenth", "sixteenth", "seventeenth", 
  130.                "eighteenth","nineteenth"};
  131.  
  132.     static char *ord10[] = {"", "", "twenty","thirty","forty","fifty","sixty",
  133.                 "seventy", "eighty","ninety"};
  134.     
  135.     static char *sord10[] = {"", "", "twentieth", "thirtieth", "fortieth",
  136.                  "fiftieth", "sixtieth","seventieth", "eightieth",
  137.                  "ninetieth"};
  138.  
  139.     static char *num1[] = {"", "one","two","three","four","five","six",
  140.                "seven","eight","nine","ten",
  141.                "eleven","twelve","thirteen","fourteen","fifteen",
  142.                "sixteen", "seventeen","eighteen","nineteen"};
  143.  
  144.     static char *num10[] = {"", "", "twenty","thirty","forty","fifty","sixty",
  145.                "seventy", "eighty","ninety"};
  146.  
  147.     #include "parse_english.c"      * This parse.c file *
  148.  
  149. #endif
  150.   
  151.   When all these things are defined parse_command() works best and most
  152.   efficient. What follows is the docs for how to use it from LPC:
  153.  
  154.  
  155.   Doc for LPC function
  156.  
  157. int parse_command(string, object/object*, string, destargs...)
  158.  
  159.             Returns 1 if pattern matches
  160.  
  161.     string        Given command
  162.  
  163.     object*        if arr 
  164.     object            array holding the accessible objects
  165.             if ob
  166.                 object from which to recurse and create
  167.                 the list of accessible objects, normally
  168.                 ob = environment(this_player())
  169.     string        Parsepattern as list of words and formats:
  170.             Example string = " 'get' / 'take' %i "
  171.             Syntax:
  172.                 'word'         obligatory text
  173.                 [word]        optional text
  174.                 /        Alternative marker
  175.                 %o        Single item, object
  176.                 %l        Living objects
  177.                 %s        Any text
  178.                 %w              Any word
  179.                 %p        One of a list (prepositions)
  180.                 %i        Any items
  181.                 %d              Number 0- or tx(0-99)
  182.  
  183.     destargs    This is the list of result variables as in sscanf
  184.             One variable is needed for each %_
  185.             The return types of different %_ is:
  186.             %o    Returns an object
  187.             %s    Returns a string of words
  188.             %w      Returns a string of one word
  189.             %p    Can on entry hold a list of word in array
  190.                 or an empty variable
  191.                 Returns:
  192.                    if empty variable: a string
  193.                    if array: array[0]=matched word
  194.             %i    Returns a special array on the form:
  195.                 [0] = (int) +(wanted) -(order) 0(all)
  196.                 [1..n] (object) Objectpointers    
  197.             %l    Returns a special array on the form:
  198.                 [0] = (int) +(wanted) -(order) 0(all)
  199.                 [1..n] (object) Objectpointers
  200.                                 These are only living objects.
  201.             %d      Returns a number
  202.  
  203.   The only types of % that uses all the loaded information from the objects
  204.   are %i and %l. These are in fact identical except that %l filters out
  205.   all nonliving objects from the list of objects before trying to parse.
  206.  
  207.   The return values of %i and %l is also the most complex. They return an
  208.   array consisting of first a number and then all possible objects matching.
  209.   As the typical string matched by %i/%l looks like: 'three red roses',
  210.   'all nasty bugs' or 'second blue sword' the number indicates which 
  211.   of these numerical constructs was matched:
  212.  
  213.          if numeral >0 then three, four, five etc were matched
  214.          if numeral <0 then second, twentyfirst etc were matched
  215.          if numeral==0 then 'all' or a generic plural form such as 'apples'
  216.                             were matched.
  217.  
  218.   NOTE!
  219.        The efun makes no semantic implication on the given numeral. It does
  220.        not matter if 'all apples' or 'second apple' is given. A %i will
  221.        return ALL possible objects matching in the array. It is up to the
  222.        caller to decide what 'second' means in a given context.
  223.  
  224.        Also when given an object and not an explicit array of objects the
  225.        entire recursive inventory of the given object is searched. It is up
  226.        to the caller to decide which of the objects are actually visible
  227.        meaning that 'second' might not at all mean the second object in
  228.        the returned array of objects.
  229.             
  230. Example:
  231.  
  232.  if (parse_command("spray car",environment(this_player()),
  233.                       " 'spray' / 'paint' [paint] %i ",items))  
  234.  {
  235.       If the pattern matched then items holds a return array as described
  236.         under 'destargs' %i above.
  237.      
  238.  }
  239.  
  240.  BUGS / Features
  241. :
  242.  
  243.  Patterns of type: "%s %w %i"
  244.    Might not work as one would expect. %w will always succeed so the arg
  245.    corresponding to %s will always be empty.
  246.  
  247.  Patterns of the type: 'word' and [word]
  248.    The 'word' can not contain spaces. It must be a single word. This is so
  249.    because the pattern is exploded on " " (space) and a pattern element can
  250.    therefore not contain spaces.
  251.             This will be fixed in the future
  252.  
  253.  
  254. */ 
  255.  
  256. /* Some useful string macros
  257. */
  258. #define EQ(x,y) (strcmp(x,y)==0)
  259. #define EQN(x,y) (strncmp(x,y,strlen(x))==0)
  260. #define EMPTY(x) (strcmp(x,"")==0)
  261.  
  262.  
  263. /* Function in LPC which returns a list of ids 
  264. */
  265. #define QGET_ID "parse_command_id_list"        
  266.  
  267. /* Function in LPC which returns a list of plural ids 
  268. */
  269. #define QGET_PLURID "parse_command_plural_id_list"   
  270.  
  271. /* Function in LPC which returns a list of adjectiv ids 
  272. */
  273. #define QGET_ADJID "parse_command_adjectiv_id_list" 
  274.  
  275. /* Function in LPC which returns a list of prepositions
  276. */
  277. #define QGET_PREPOS "parse_command_prepos_list" 
  278.  
  279. /* Function in LPC which returns the 'all' word
  280. */
  281. #define QGET_ALLWORD "parse_command_all_word"
  282.  
  283. /* Global vectors for 'caching' of ids
  284.  
  285.    The main 'parse' routine stores these on call, making the entire
  286.    parse_command() reentrant.
  287. */
  288. static struct vector    *gId_list    = 0;
  289. static struct vector    *gPluid_list    = 0;
  290. static struct vector    *gAdjid_list    = 0;
  291. static struct vector    *gId_list_d    = 0;  /* From master */
  292. static struct vector    *gPluid_list_d    = 0;  /* From master */
  293. static struct vector    *gAdjid_list_d    = 0;  /* From master */
  294. static struct vector    *gPrepos_list    = 0;  /* From master */
  295. static char         *gAllword       = 0;  /* From master */
  296.  
  297. /*
  298.  * Function name:     load_lpc_info
  299.  * Description:        Loads relevant information from a given object.
  300.  *            This is the ids, plural ids and adjectiv ids. This
  301.  *            is the only calls to LPC objects other than the
  302.  *                      master object that occur within the efun
  303.  *                      parse_command().
  304.  * Arguments:        ix: Index in the array
  305.  *            ob: The object to call for information.
  306.  */
  307. void load_lpc_info(ix, ob)
  308.     int    ix;
  309.     struct object *ob;
  310. {
  311.     struct vector *tmp, *sing;
  312.     struct svalue sval, *ret;
  313.     int il, make_plural = 0;
  314.     char *str;
  315.     char *parse_to_plural();
  316.  
  317.     if (!ob)
  318.     return;
  319.  
  320.     if (gPluid_list && 
  321.     gPluid_list->size > ix && 
  322.     gPluid_list->item[ix].type == T_NUMBER &&
  323.     gPluid_list->item[ix].u.number == 0)
  324.     {
  325.     ret = apply(QGET_PLURID, ob, 0);
  326.     if (ret && ret->type == T_POINTER) 
  327.         assign_svalue_no_free(&gPluid_list->item[ix], ret);
  328.     else 
  329.     {
  330.         make_plural = 1;
  331.         gPluid_list->item[ix].u.number = 1;
  332.     }
  333.     }
  334.  
  335.     if (gId_list && 
  336.     gId_list->size > ix && 
  337.     gId_list->item[ix].type == T_NUMBER &&
  338.     gId_list->item[ix].u.number == 0)
  339.     {
  340.     ret = apply(QGET_ID, ob, 0);
  341.     if (ret && ret->type == T_POINTER)
  342.     {
  343.         assign_svalue_no_free(&gId_list->item[ix], ret);
  344.         if (make_plural)
  345.         {
  346.         tmp = allocate_array(ret->u.vec->size);
  347.         sing = ret->u.vec;
  348.         for (il = 0; il < tmp->size; il++)
  349.         {
  350.             if (sing->item[il].type == T_STRING)
  351.             {
  352.             str = parse_to_plural(sing->item[il].u.string);
  353.             sval.type = T_STRING;
  354.             sval.string_type = STRING_MALLOC;
  355.             sval.u.string = string_copy(str);
  356.             assign_svalue_no_free(&tmp->item[il],&sval);
  357.             }
  358.         }
  359.         sval.type = T_POINTER;
  360.         sval.u.vec = tmp;
  361.         assign_svalue_no_free(&gPluid_list->item[ix], &sval);
  362.         }
  363.     }
  364.     else
  365.     {
  366.         gId_list->item[ix].u.number = 1;
  367.     }
  368.     }
  369.  
  370.     if (gAdjid_list && 
  371.     gAdjid_list->size > ix &&     
  372.     gAdjid_list->item[ix].type == T_NUMBER &&
  373.     gAdjid_list->item[ix].u.number == 0)
  374.     {
  375.     ret = apply(QGET_ADJID, ob, 0);
  376.     if (ret && ret->type == T_POINTER)
  377.         assign_svalue_no_free(&gAdjid_list->item[ix], ret);
  378.     else
  379.         gAdjid_list->item[ix].u.number = 1;
  380.     }
  381. }
  382.  
  383. /* Main function, called from interpret.c
  384. */
  385.  
  386. /*
  387.  * Function name:     parse
  388.  * Description:        The main function for the efun: parse_command()
  389.  *            It parses a given command using a given pattern and
  390.  *            a set of objects (see args below). For details
  391.  *            see LPC documentation of the efun.
  392.  * Arguments:        cmd: The command to parse
  393.  *            ob_or_array: A list of objects or one object from 
  394.  *                         which to make a list of objects by
  395.  *                     using the objects deep_inventory
  396.  *            pattern: The given parse pattern somewhat like sscanf
  397.  *                     but with different %-codes, see efun docs.
  398.  *            stack_args: Pointer to destination arguments.
  399.  *            num_arg: Number of destination arguments.
  400.  * Returns:        True if command matched pattern.
  401.  */
  402. int parse (cmd, ob_or_array, pattern, stack_args, num_arg)
  403.     char         *cmd;              /* Command to parse */
  404.     struct svalue     *ob_or_array;      /* Object or array of objects */
  405.     char        *pattern;    /* Special parsing pattern */
  406.     struct svalue     *stack_args;    /* Pointer to lvalue args on stack */
  407.     int         num_arg;    /* Number of args on stack */
  408. {
  409.     struct vector    *obvec, *patvec, *wvec;
  410.     struct vector    *old_id, *old_plid, *old_adjid;
  411.     struct vector    *old_id_d, *old_plid_d, *old_adjid_d, *old_prepos;
  412.     char        *old_allword;     
  413.     int            pix, cix, six, fail, fword, ocix, fpix;
  414.     struct svalue    *pval;
  415.     void        check_for_destr();    /* In interpret.c */
  416.     struct svalue    *sub_parse();
  417.     struct svalue    *slice_words();
  418.     void        stack_put();
  419.     struct vector    *deep_inventory();
  420.  
  421.     /*
  422.      * Pattern and commands can not be empty
  423.      */
  424.     if (!strlen(cmd) || !strlen(pattern))
  425.     return 0;
  426.  
  427.     wvec = explode_string(cmd," ");        /* Array of words in command */
  428.     patvec = explode_string(pattern," ");  /* Array of pattern elements */
  429.  
  430.     /*
  431.      * Explode can return '0'. 
  432.      */
  433.     if (!wvec)
  434.     wvec = allocate_array(0);
  435.     if (!patvec)
  436.     patvec = allocate_array(0);
  437.  
  438.     wvec->ref++;         /* Do not lose these arrays */
  439.     patvec->ref++;
  440.  
  441.     if (ob_or_array->type == T_POINTER)
  442.     obvec = ob_or_array->u.vec;
  443.     else if (ob_or_array->type == T_OBJECT)
  444.     obvec = deep_inventory(ob_or_array->u.ob, 1); /* 1 == ob + deepinv */
  445.     else
  446.     {
  447.     obvec = 0;
  448.     error("Bad second argument to parse_command()\n");
  449.     }
  450.  
  451.     check_for_destr(obvec);
  452.  
  453.     obvec->ref++;
  454.  
  455.     /* Copy and  make space for id arrays
  456.     */
  457.     old_id      = gId_list; 
  458.     old_plid    = gPluid_list; 
  459.     old_adjid   = gAdjid_list;
  460.     old_id_d      = gId_list_d; 
  461.     old_plid_d    = gPluid_list_d; 
  462.     old_adjid_d   = gAdjid_list_d;
  463.     old_prepos    = gPrepos_list;
  464.     old_allword   = gAllword;
  465.  
  466.     gId_list    = allocate_array(obvec->size);
  467.     gPluid_list  = allocate_array(obvec->size);
  468.     gAdjid_list = allocate_array(obvec->size);
  469.     
  470.     /* Get the default ids of 'general references' from master object
  471.     */
  472.     pval = apply_master_ob(QGET_ID,0);
  473.     if (pval && pval->type == T_POINTER)
  474.     {
  475.     gId_list_d = pval->u.vec;
  476.     pval->u.vec->ref++;
  477.     }
  478.     else
  479.     gId_list_d = 0;
  480.  
  481.     pval = apply_master_ob(QGET_PLURID,0);
  482.     if (pval && pval->type == T_POINTER)    
  483.     {
  484.     gPluid_list_d = pval->u.vec;
  485.     pval->u.vec->ref++;
  486.     }
  487.     else
  488.     gPluid_list_d = 0;
  489.  
  490.     pval = apply_master_ob(QGET_ADJID,0);
  491.     if (pval && pval->type == T_POINTER)
  492.     {
  493.     gAdjid_list_d = pval->u.vec;
  494.     pval->u.vec->ref++;
  495.     }
  496.     else
  497.     gAdjid_list_d = 0;
  498.  
  499.     pval = apply_master_ob(QGET_PREPOS,0);
  500.     if (pval && pval->type == T_POINTER)
  501.     {
  502.     gPrepos_list = pval->u.vec;
  503.     pval->u.vec->ref++;
  504.     }
  505.     else
  506.     gPrepos_list = 0;
  507.  
  508.     pval = apply_master_ob(QGET_ALLWORD,0);
  509.     if (pval && pval->type == T_STRING)
  510.     gAllword = string_copy(pval->u.string);
  511.     else
  512.     gAllword = 0;
  513.  
  514.     /* Loop through the pattern. Handle %s but not '/'
  515.     */
  516.     for (six=0,cix=0,fail=0,pix=0; pix < patvec->size; pix++)
  517.     {
  518.     pval = 0; 
  519.     fail = 0; 
  520.  
  521.     if (EQ(patvec->item[pix].u.string,"%s")) {
  522.         if (pix == (patvec->size-1))
  523.         {
  524.         pval = slice_words(wvec,cix,wvec->size-1);
  525.         cix = wvec->size;
  526.         }
  527.         else {
  528.         ocix = fword = cix; fpix = ++pix;
  529.         do {
  530.             fail = 0;
  531.             pval = sub_parse(obvec, patvec, &pix, wvec, &cix, &fail,
  532.                      (six<num_arg)?stack_args[six].u.lvalue:0);
  533.             if (fail) {
  534.             cix = ++ocix;
  535.             pix = fpix;
  536.             }
  537.         } while ((fail) && (cix<wvec->size));
  538.  
  539.         if (!fail) {
  540.             stack_put(pval,stack_args,six+1,num_arg);
  541.             pval = slice_words(wvec,fword,ocix-1);
  542.             stack_put(pval,stack_args,six++,num_arg);
  543.             pval = 0; 
  544.         }
  545.         }
  546.     }
  547.  
  548.     else if (!EQ(patvec->item[pix].u.string,"/")) {
  549.  
  550.         pval = sub_parse(obvec, patvec, &pix, wvec, &cix, &fail,
  551.                  (six<num_arg)?stack_args[six].u.lvalue:0);
  552.     }
  553.  
  554.     if ((!fail) && (pval))
  555.         stack_put(pval,stack_args,six++,num_arg);
  556.     else if (fail)
  557.         break;
  558.     }
  559.     
  560.     /* Also fail when there is words left to parse and pattern exhausted
  561.     */
  562.     if (cix < wvec->size)
  563.     fail = 1;
  564.  
  565.     /* Delete and free the id arrays
  566.     */
  567.     if (gId_list) 
  568.     {
  569.     gId_list->ref--;
  570.     free_vector(gId_list);
  571.     }
  572.     if (gPluid_list) 
  573.     {
  574.     gPluid_list->ref--;
  575.     free_vector(gPluid_list);
  576.     }
  577.     if (gAdjid_list) 
  578.     {
  579.     gAdjid_list->ref--;
  580.     free_vector(gAdjid_list);
  581.     }
  582.     if (gId_list_d) 
  583.     {
  584.     gId_list_d->ref--;
  585.     free_vector(gId_list_d); 
  586.     }
  587.     if (gPluid_list_d) 
  588.     {
  589.     gPluid_list_d->ref--;
  590.     free_vector(gPluid_list_d); 
  591.     }
  592.     if (gAdjid_list_d) 
  593.     {
  594.     gAdjid_list_d->ref--;
  595.     free_vector(gAdjid_list_d);
  596.     }
  597.     if (gPrepos_list) 
  598.     {
  599.     gPrepos_list->ref--;
  600.     free_vector(gPrepos_list);
  601.     }
  602.     if (gAllword)
  603.     free(gAllword);
  604.  
  605.     gId_list_d         = old_id_d;
  606.     gPluid_list_d    = old_plid_d;
  607.     gAdjid_list_d     = old_adjid_d;
  608.     gPrepos_list     = old_prepos;
  609.     gId_list         = old_id;     
  610.     gPluid_list     = old_plid; 
  611.     gAdjid_list     = old_adjid;
  612.     gAllword         = old_allword;
  613.  
  614.     wvec->ref--; 
  615.     patvec->ref--;
  616.     obvec->ref--;
  617.     free_vector(wvec);
  618.     free_vector(patvec);
  619.  
  620.     /*
  621.      * A vector we made should be freed
  622.      */
  623.     if (ob_or_array->type == T_OBJECT)
  624.     {
  625.     obvec->ref--;
  626.     free_vector(obvec); 
  627.     }
  628.  
  629.     return !fail;
  630. }
  631.  
  632. /*
  633.  * Function name:     stack_put
  634.  * Description:        Puts an svalue on the stack.
  635.  * Arguments:        pval: Value to put
  636.  *            sp: Stackpointer
  637.  *            pos: Position on stack to put value
  638.  *            max: The number of args on the stack
  639.  */
  640. void stack_put(pval, sp, pos, max)
  641.     struct svalue    *pval;
  642.     struct svalue    *sp;
  643.     int            pos, max;
  644. {
  645.     if (pos >= max)
  646.     return;
  647.  
  648.     if ((pval) && (sp[pos].type == T_LVALUE))
  649.     assign_svalue(sp[pos].u.lvalue, pval);
  650. }
  651.  
  652. /*
  653.  * Function name:     slice_words
  654.  * Description:        Gives an imploded string of words from an array
  655.  * Arguments:        wvec: array of words
  656.  *            from: First word to use
  657.  *            to:   Last word to use
  658.  * Returns:        A pointer to a static svalue now containing string.
  659.  */
  660. struct svalue *slice_words(wvec, from, to)
  661.     struct vector    *wvec;
  662.     int            from, to;
  663. {
  664.     struct vector    *slice;
  665.     char        *tx;
  666.     static struct svalue stmp;
  667.  
  668.     if (from>to)
  669.     return 0;
  670.     
  671.     slice = slice_array(wvec, from, to);
  672.  
  673.     if (slice->size)
  674.     tx = implode_string(slice," ");
  675.     else
  676.     tx = 0;
  677.  
  678.     free_vector(slice);
  679.     if (tx) {
  680.     stmp.type = T_STRING;
  681.     stmp.string_type = STRING_SHARED;
  682.     stmp.u.string = make_shared_string(tx);
  683.     return &stmp;
  684.     }
  685.     else
  686.     return 0;
  687. }
  688.  
  689. /*
  690.  * Function name:     sub_parse
  691.  * Description:        Parses a vector of words against a pattern. Gives
  692.  *            result as an svalue. Sets fail if parsing fails and
  693.  *            updates pointers in pattern and word vectors. It
  694.  *            handles alternate patterns but not "%s"
  695.  */
  696. struct svalue *sub_parse(obvec, patvec, pix_in, wvec, cix_in, fail, sp)
  697.     struct vector    *obvec;
  698.     struct vector    *patvec;
  699.     int            *pix_in;
  700.     struct vector    *wvec;
  701.     int            *cix_in;
  702.     int            *fail;
  703.     struct svalue    *sp;        /* prepos_parse needs it */
  704. {
  705.     int        cix, pix, subfail;
  706.     struct svalue    *pval;
  707.     struct svalue    *one_parse();
  708.  
  709.     if (*cix_in == wvec->size) {
  710.     *fail = 1;
  711.     return 0;
  712.     }
  713.  
  714.     cix = *cix_in; pix = *pix_in; subfail = 0;
  715.  
  716.     pval = one_parse(obvec, patvec->item[pix].u.string,
  717.              wvec, &cix, &subfail, sp);
  718.  
  719.     while (subfail)
  720.     {
  721.     pix++;
  722.     cix = *cix_in;
  723.  
  724.     while ((pix < patvec->size) && (EQ(patvec->item[pix].u.string,"/")))
  725.     {
  726.         subfail = 0;
  727.         pix++;
  728.     }
  729.  
  730.     if ((!subfail) && (pix<patvec->size))
  731.         pval = one_parse(obvec, patvec->item[pix].u.string, wvec, &cix, 
  732.                  &subfail, sp);
  733.     else
  734.     {
  735.         *fail = 1; *pix_in = pix-1;
  736.         return 0;
  737.     }
  738.     }
  739.  
  740.     /* If there is alternatives skip them
  741.     */
  742.     if ((pix+1 < patvec->size) && (EQ(patvec->item[pix+1].u.string,"/"))) {
  743.     while ((pix+1 <patvec->size) &&
  744.            (EQ(patvec->item[pix+1].u.string,"/"))) {
  745.            pix += 2;
  746.     }
  747.     pix++; /* Skip last alternate after last '/' */
  748.     if (pix>=patvec->size)
  749.         pix = patvec->size-1;
  750.     }
  751.  
  752.     *cix_in = cix;
  753.     *pix_in = pix;
  754.     *fail = 0;
  755.     return pval;
  756. }
  757.     
  758.  
  759. /*
  760.  * Function name:     one_parse
  761.  * Description:        Checks one parse pattern to see if match. Consumes
  762.  *            needed number of words from wvec.
  763.  * Arguments:        obvec: Vector of objects relevant to parse
  764.  *            pat: The pattern to match against.
  765.  *            wvec: Vector of words in the command to parse
  766.  *            cix_in: Current word in commandword vector
  767.  *            fail: Fail flag if parse did not match
  768.  *            prep_param: Only used on %p (see prepos_parse)
  769.  * Returns:        svalue holding result of parse.
  770.  */
  771. struct svalue *one_parse(obvec, pat, wvec, cix_in, fail, prep_param)
  772.     struct vector    *obvec;
  773.     char        *pat;
  774.     struct vector    *wvec;
  775.     int            *cix_in;
  776.     int            *fail;
  777.     struct svalue    *prep_param;
  778. {
  779.     char ch;
  780.     struct svalue    *pval;
  781.     static struct svalue stmp;
  782.     char        *str1, *str2;
  783.     struct svalue    *item_parse();
  784.     struct svalue    *living_parse();
  785.     struct svalue    *single_parse();
  786.     struct svalue    *prepos_parse();
  787.     struct svalue    *number_parse();
  788.  
  789.     if (*cix_in == wvec->size) {
  790.     *fail = 1;
  791.     return 0;
  792.     }
  793.  
  794.     ch=pat[0]; 
  795.     if (ch=='%') {
  796.     ch=((isupper(pat[1]))?tolower(pat[1]):pat[1]);
  797.     }
  798.  
  799.     pval = 0;
  800.  
  801.     switch (ch) {
  802.     case 'i':
  803.     pval = item_parse(obvec, wvec, cix_in, fail);
  804.     break;
  805.  
  806.     case 'l':
  807.     pval = living_parse(obvec, wvec, cix_in, fail);
  808.     break;
  809.  
  810.     case 's':
  811.     *fail = 0; /* This is double %s in pattern, skip it */
  812.     break;
  813.  
  814.     case 'w':
  815.     stmp.type = T_STRING;
  816.     stmp.string_type = STRING_SHARED;
  817.     stmp.u.string = make_shared_string(wvec->item[*cix_in].u.string);
  818.     pval = &stmp;
  819.     (*cix_in)++;
  820.     *fail = 0;
  821.     break;
  822.  
  823.     case 'o':
  824.     pval = single_parse(obvec, wvec, cix_in, fail);
  825.     break;
  826.  
  827.     case 'p':
  828.     pval = prepos_parse(wvec, cix_in, fail, prep_param);
  829.     break;
  830.  
  831.     case 'd':
  832.     pval = number_parse(obvec, wvec, cix_in, fail);
  833.     break;
  834.  
  835.     case '\'':
  836.     str1 = &pat[1]; str2 = wvec->item[*cix_in].u.string;
  837.     if ((strncmp(str1,str2,strlen(str1)-1) == 0) &&
  838.         (strlen(str1) == strlen(str2)+1)) {
  839.         *fail = 0;
  840.         (*cix_in)++;
  841.     }
  842.     else
  843.         *fail = 1;
  844.     break;
  845.  
  846.     case '[':
  847.     str1 = &pat[1]; str2 = wvec->item[*cix_in].u.string;
  848.     if ((strncmp(str1,str2,strlen(str1)-1) == 0) &&
  849.         (strlen(str1) == strlen(str2)+1)) {
  850.         (*cix_in)++;
  851.     }
  852.     *fail = 0;
  853.     break;
  854.  
  855.     default:
  856.     *fail = 0; /* Skip invalid patterns */
  857.     }
  858.     return pval;
  859. }
  860.  
  861.  
  862. #ifndef PARSE_FOREIGN
  863.  
  864.     static char *ord1[] = {"", "first", "second", "third", "fourth", "fifth",
  865.                "sixth", "seventh", "eighth", "nineth", "tenth",
  866.                "eleventh", "twelfth", "thirteenth", "fourteenth",
  867.                "fifteenth", "sixteenth", "seventeenth", 
  868.                "eighteenth","nineteenth"};
  869.  
  870.     static char *ord10[] = {"", "", "twenty","thirty","forty","fifty","sixty",
  871.                 "seventy", "eighty","ninety"};
  872.     
  873.     static char *sord10[] = {"", "", "twentieth", "thirtieth", "fortieth",
  874.                  "fiftieth", "sixtieth","seventieth", "eightieth",
  875.                  "ninetieth"};
  876.  
  877.     static char *num1[] = {"", "one","two","three","four","five","six",
  878.                "seven","eight","nine","ten",
  879.                "eleven","twelve","thirteen","fourteen","fifteen",
  880.                "sixteen", "seventeen","eighteen","nineteen"};
  881.  
  882.     static char *num10[] = {"", "", "twenty","thirty","forty","fifty","sixty",
  883.                "seventy", "eighty","ninety"};
  884. #endif
  885.  
  886. /*
  887.  * Function name:     number_parse
  888.  * Description:        Tries to interpret the word in wvec as a numeral
  889.  *            descriptor and returns the result on the form:
  890.  *            ret.type == T_NUMBER
  891.  *                num == 0, 'zero', '0', gAllword
  892.  *                num > 0, one, two, three etc or numbers given
  893.  *                num < 0, first, second,third etc given
  894.  * Arguments:        obvec: Vector of objects relevant to parse
  895.  *            wvec: Vector of words in the command to parse
  896.  *            cix_in: Current word in commandword vector
  897.  *            fail: Fail flag if parse did not match
  898.  * Returns:        svalue holding result of parse.
  899.  */
  900. struct svalue *number_parse(obvec, wvec, cix_in, fail)
  901.     struct vector     *obvec;
  902.     struct vector     *wvec;
  903.     int            *cix_in;
  904.     int            *fail;
  905. {
  906.     int cix, ten, ones, num;
  907.     char buf[100];
  908.     static struct svalue stmp;
  909.  
  910.     cix = *cix_in; *fail = 0;
  911.  
  912.     if (sscanf(wvec->item[cix].u.string,"%d",&num)) {
  913.     if (num>=0) {
  914.         (*cix_in)++;
  915.         stmp.type = T_NUMBER;
  916.         stmp.u.number = num;
  917.         return &stmp;
  918.     }
  919.     *fail = 1;
  920.     return 0; /* Only nonnegative numbers */
  921.     }
  922.  
  923.     if (gAllword && (strcmp(wvec->item[cix].u.string,gAllword) == 0))
  924.     {
  925.     (*cix_in)++;
  926.     stmp.type = T_NUMBER;
  927.     stmp.u.number = 0;
  928.     return &stmp;
  929.     }
  930.     
  931.     for (ten=0;ten<10;ten++) for(ones=0;ones<10;ones++) {
  932.     sprintf(buf,"%s%s", num10[ten], (ten>1)?num1[ones]:num1[ten*10+ones]);
  933.     if (EQ(buf,wvec->item[cix].u.string)) {
  934.         (*cix_in)++;
  935.         stmp.type = T_NUMBER;
  936.         stmp.u.number = ten*10+ones;
  937.         return &stmp;
  938.     }
  939.     }
  940.  
  941.     for (ten=0;ten<10;ten++) for(ones=0;ones<10;ones++) {
  942.     sprintf(buf,"%s%s", (ones)?ord10[ten]:sord10[ten],
  943.         (ten>1)?ord1[ones]:ord1[ten*10+ones]);
  944.     if (EQ(buf,wvec->item[cix].u.string)) {
  945.         (*cix_in)++;
  946.         stmp.type = T_NUMBER;
  947.         stmp.u.number = -(ten*10+ones);
  948.         return &stmp;
  949.     }
  950.     }
  951.  
  952.     *fail = 1;
  953.     return 0;
  954. }
  955.  
  956.  
  957. /*
  958.  * Function name:     item_parse
  959.  * Description:        Tries to match as many objects in obvec as possible
  960.  *            onto the description given in commandvector wvec.
  961.  *            Also finds numeral description if one exist and returns
  962.  *            that as first element in array:
  963.  *            ret[0].type == T_NUMBER
  964.  *                num == 0, 'all' or 'general plural given'
  965.  *                num > 0, one, two, three etc given
  966.  *                num < 0, first, second,third etc given
  967.  *            ret[1-n] == Selected objectpointers from obvec
  968.  * Arguments:        obvec: Vector of objects relevant to parse
  969.  *            wvec: Vector of words in the command to parse
  970.  *            cix_in: Current word in commandword vector
  971.  *            fail: Fail flag if parse did not match
  972.  * Returns:        svalue holding result of parse.
  973.  */
  974. struct svalue *item_parse(obvec, wvec, cix_in, fail)
  975.     struct vector     *obvec;
  976.     struct vector     *wvec;
  977.     int            *cix_in;
  978.     int            *fail;
  979. {
  980.     struct vector    *tmp, *ret;
  981.     struct svalue    *pval;
  982.     static struct svalue stmp;
  983.     int            cix, tix, obix, plur_flag, max_cix, match_all;
  984.     int            match_object();
  985.     void        load_lpc_info();
  986.  
  987.  
  988.     tmp = allocate_array(obvec->size + 1);
  989.     if (pval = number_parse(obvec, wvec, cix_in, fail))
  990.     assign_svalue_no_free(&tmp->item[0],pval);
  991.  
  992.     if ((pval) && (pval->u.number>1))
  993.     {
  994.     plur_flag = 1;
  995.     match_all = 0;
  996.     }
  997.     else if ((pval) && (pval->u.number == 0))
  998.     {
  999.     plur_flag = 1;
  1000.     match_all = 1;
  1001.     }
  1002.     else 
  1003.     {
  1004.     plur_flag = 0;
  1005.     match_all = 0;
  1006.     }
  1007.  
  1008.     for (max_cix = *cix_in, tix=1, obix=0; obix < obvec->size; obix++) {
  1009.     *fail = 0; cix = *cix_in;
  1010.     if (obvec->item[obix].type != T_OBJECT)
  1011.         continue;
  1012.     if (cix == wvec->size && match_all)
  1013.     {
  1014.         assign_svalue_no_free(&tmp->item[tix++],&obvec->item[obix]);
  1015.         continue;
  1016.     }        
  1017.     load_lpc_info(obix,obvec->item[obix].u.ob);
  1018.     if (match_object(obix, wvec, &cix, &plur_flag)) {
  1019.         assign_svalue_no_free(&tmp->item[tix++],&obvec->item[obix]);
  1020.         max_cix = (max_cix<cix)?cix:max_cix;
  1021.     }
  1022.     }
  1023.  
  1024.     if (tix<2) {
  1025.     *fail = 1;
  1026.     free_vector(tmp);
  1027.     if (pval) (*cix_in)--;
  1028.     return 0;
  1029.     }
  1030.     else
  1031.     {
  1032.     if (*cix_in < wvec->size)
  1033.         *cix_in = max_cix + 1;
  1034.     ret = slice_array(tmp,0,tix-1);
  1035.     if (!pval) {
  1036.         ret->item[0].type = T_NUMBER;
  1037.         ret->item[0].u.number = plur_flag?0:1;
  1038.     }
  1039.     free_vector(tmp);
  1040.     }
  1041.  
  1042.     stmp.type = T_POINTER;
  1043.     stmp.u.vec = ret;
  1044.     return &stmp;
  1045. }
  1046.  
  1047. /*
  1048.  * Function name:     living_parse
  1049.  * Description:        Tries to match as many living objects in obvec as
  1050.  *            possible onto the description given in the command-
  1051.  *            vector wvec.
  1052.  *            Also finds numeral description if one exist and returns
  1053.  *            that as first element in array:
  1054.  *            ret[0].type == T_NUMBER
  1055.  *                num == 0, 'all' or 'general plural given'
  1056.  *                num > 0, one, two, three etc given
  1057.  *                num < 0, first, second,third etc given
  1058.  *            ret[1-n] == Selected objectpointers from obvec
  1059.  *            If not found in obvec a find_player and
  1060.  *            lastly a find_living is done. These will return an
  1061.  *            objecttype svalue.
  1062.  * Arguments:        obvec: Vector of objects relevant to parse
  1063.  *            wvec: Vector of words in the command to parse
  1064.  *            cix_in: Current word in commandword vector
  1065.  *            fail: Fail flag if parse did not match
  1066.  * Returns:        svalue holding result of parse.
  1067.  */
  1068. struct svalue *living_parse(obvec, wvec, cix_in, fail)
  1069.     struct vector     *obvec;
  1070.     struct vector     *wvec;
  1071.     int            *cix_in;
  1072.     int            *fail;
  1073. {
  1074.     struct vector    *live;
  1075.     struct svalue    *pval;
  1076.     static struct svalue stmp;
  1077.     struct object    *ob;
  1078.     int            obix, tix;
  1079.  
  1080.     live = allocate_array(obvec->size); tix = 0; *fail = 0;
  1081.  
  1082.     for (obix=0;obix<obvec->size;obix++) 
  1083.     if (obvec->item[obix].u.ob->flags & O_ENABLE_COMMANDS)
  1084.         assign_svalue_no_free(&live->item[tix++],&obvec->item[obix]);
  1085.  
  1086.     if (tix) {
  1087.     pval = item_parse(live, wvec, cix_in, fail);
  1088.     if (pval) {
  1089.         free_vector(live);
  1090.         return pval;
  1091.     }
  1092.     }
  1093.     
  1094.     free_vector(live);
  1095.  
  1096.     /* find_player */
  1097.     ob = find_living_object(wvec->item[*cix_in].u.string, 1); 
  1098.     if (!ob)
  1099.     /* find_living */
  1100.     ob = find_living_object(wvec->item[*cix_in].u.string, 0); 
  1101.  
  1102.     if (ob) {
  1103.     stmp.type = T_OBJECT;
  1104.     stmp.u.ob = ob;
  1105.     (*cix_in)++;
  1106.     return &stmp;
  1107.     }
  1108.     *fail = 1;
  1109.     return 0;
  1110. }
  1111.  
  1112. /*
  1113.  * Function name:     single_parse
  1114.  * Description:        Finds the first object in obvec fitting the description
  1115.  *            in commandvector wvec. Gives this as an objectpointer.
  1116.  * Arguments:        obvec: Vector of objects relevant to parse
  1117.  *            wvec: Vector of words in the command to parse
  1118.  *            cix_in: Current word in commandword vector
  1119.  *            fail: Fail flag if parse did not match
  1120.  * Returns:        svalue holding result of parse.
  1121.  */
  1122. struct svalue *single_parse(obvec, wvec, cix_in, fail)
  1123.     struct vector     *obvec;
  1124.     struct vector     *wvec;
  1125.     int            *cix_in;
  1126.     int            *fail;
  1127. {
  1128.     int            cix, obix, plur_flag;
  1129.     int            match_object();
  1130.     void            load_lpc_info();
  1131.  
  1132.     for (obix=0;obix<obvec->size;obix++)
  1133.     {
  1134.     *fail = 0; cix = *cix_in;
  1135.     load_lpc_info(obix,obvec->item[obix].u.ob);
  1136.     if (match_object(obix, wvec, &cix, &plur_flag))
  1137.     {
  1138.         *cix_in = cix+1;
  1139.         return &obvec->item[obix];
  1140.     }
  1141.     plur_flag = 0;
  1142.     }
  1143.     *fail = 1;
  1144.     return 0;
  1145. }
  1146.  
  1147. /*
  1148.  * Function name:     prepos_parse
  1149.  * Description:        This is a general sentencelist matcher with some hard-
  1150.  *            coded prepositions as the default list. The list is 
  1151.  *            sent as a parameter which will be replaced in the
  1152.  *            destination values. If no list is given the return
  1153.  *            value on match with the hardcoded prepositions will be
  1154.  *            string. If a list is given, the list will be returned
  1155.  *            with the matched sentence swapped to the first element.
  1156.  * Arguments:        wvec: Vector of words in the command to parse
  1157.  *            cix_in: Current word in commandword vector
  1158.  *            fail: Fail flag if parse did not match
  1159.  * Returns:        svalue holding result of parse.
  1160.  */
  1161. struct svalue *prepos_parse(wvec, cix_in, fail, prepos)
  1162.     struct vector     *wvec;
  1163.     int            *cix_in;
  1164.     int            *fail;
  1165.     struct svalue    *prepos;
  1166. {
  1167.   struct vector    *pvec, *tvec;
  1168.   static struct svalue stmp;
  1169.   char *tmp;
  1170.   int pix, tix;
  1171.  
  1172.   if ((!prepos) || (prepos->type != T_POINTER))
  1173.   {
  1174.       pvec = gPrepos_list;
  1175.   }
  1176.   else
  1177.   {
  1178.       pvec = prepos->u.vec;
  1179.   }
  1180.  
  1181.   for (pix = 0; pix < pvec->size; pix++)
  1182.   {
  1183.       if (pvec->item[pix].type != T_STRING)
  1184.       continue;
  1185.  
  1186.       tmp = pvec->item[pix].u.string;
  1187.       if (!strchr(tmp,' '))
  1188.       {
  1189.       if (EQ(tmp,wvec->item[*cix_in].u.string))
  1190.       {
  1191.           (*cix_in)++;
  1192.           break;
  1193.       }
  1194.       }
  1195.       else {
  1196.       tvec = explode_string(tmp, " ");
  1197.       for (tix=0;tix<tvec->size;tix++)
  1198.       {
  1199.           if ((*cix_in+tix >= wvec->size) ||
  1200.           (!EQ(wvec->item[*cix_in+tix].u.string,tvec->item[tix].u.string)))
  1201.           break;
  1202.       }
  1203.       if (tix = (tix == tvec->size)?1:0)
  1204.           (*cix_in)+=tvec->size;
  1205.       free_vector(tvec);
  1206.       if (tix)
  1207.           break;
  1208.       }
  1209.   }
  1210.  
  1211.   if (pix == pvec->size)
  1212.   {
  1213.       *fail = 1;
  1214.   }
  1215.   else if (pvec != gPrepos_list)
  1216.   {
  1217.       assign_svalue_no_free(&stmp,&pvec->item[0]);
  1218.       assign_svalue_no_free(&pvec->item[0],&pvec->item[pix]);
  1219.       assign_svalue_no_free(&pvec->item[pix], &stmp);
  1220.       *fail = 0;
  1221.   }
  1222.   return prepos;
  1223.  
  1224. }
  1225.  
  1226.  
  1227.  
  1228. /*
  1229.  * Function name:     match_object
  1230.  * Description:        Tests if a given object matches the description as
  1231.  *            given in the commandvector wvec.
  1232.  * Arguments:        obix: Index in id arrays for this object.
  1233.  *            wvec: Vector of words in the command to parse
  1234.  *            cix_in: Current word in commandword vector
  1235.  *            plur: This arg gets set if the noun was on pluralform
  1236.  * Returns:        True if object matches.
  1237.  */
  1238. int match_object(obix, wvec, cix_in, plur)
  1239.     int             obix;
  1240.     struct vector     *wvec;
  1241.     int            *cix_in;
  1242.     int            *plur;
  1243. {
  1244.     struct vector    *ids;
  1245.     int         il, pos, cplur, old_cix;
  1246.     char        *str;
  1247.     int            find_string();
  1248.     int            check_adjectiv();
  1249.  
  1250.     for (cplur = (*plur * 2); cplur<4; cplur++)
  1251.     {
  1252.     switch (cplur) 
  1253.     {
  1254.     case 0:
  1255.         if (!gId_list_d)
  1256.         continue;
  1257.         ids = gId_list_d;
  1258.         break;
  1259.  
  1260.     case 1:
  1261.         if (!gId_list || 
  1262.         gId_list->size <= obix || 
  1263.         gId_list->item[obix].type != T_POINTER)
  1264.         continue;
  1265.         ids = gId_list->item[obix].u.vec;
  1266.         break;
  1267.  
  1268.     case 2:
  1269.         if (!gPluid_list_d)
  1270.         continue;
  1271.         ids = gPluid_list_d;
  1272.         break;
  1273.  
  1274.     case 3:
  1275.         if (!gPluid_list || 
  1276.         gPluid_list->size <= obix || 
  1277.         gPluid_list->item[obix].type != T_POINTER)
  1278.         continue;
  1279.         ids = gPluid_list->item[obix].u.vec;
  1280.         break;
  1281.  
  1282.     default:
  1283.         ids = 0;
  1284.  
  1285.     }
  1286.  
  1287.     for (il = 0; il < ids->size; il++)
  1288.     {
  1289.         if (ids->item[il].type == T_STRING)
  1290.         {
  1291.         str = ids->item[il].u.string;  /* A given id of the object */
  1292.         old_cix = *cix_in;
  1293.         if ((pos = find_string(str, wvec, cix_in)) >= 0)
  1294.         {
  1295.             if (pos == old_cix)
  1296.             {
  1297.             if (cplur > 1)
  1298.                 *plur = 1;
  1299.             return 1;
  1300.             }
  1301.             else if (check_adjectiv(obix, wvec, old_cix, pos-1))
  1302.             {
  1303.             if (cplur > 1)
  1304.                 *plur = 1;
  1305.             return 1;
  1306.             }
  1307.         }
  1308.         *cix_in = old_cix;
  1309.         }
  1310.     }
  1311.     }
  1312.     return 0;
  1313. }
  1314.             
  1315.         
  1316. /*
  1317.  * Function name:     find_string
  1318.  * Description:        Finds out if a given string exist within an
  1319.  *            array of words.
  1320.  * Arguments:        str: String of some words 
  1321.  *            wvec: Array of words
  1322.  *            cix_in: Startpos in word array
  1323.  * Returns:        Pos in array if string found or -1
  1324.  */
  1325. int find_string(str, wvec, cix_in)
  1326.     char        *str;
  1327.     struct vector    *wvec;
  1328.     int            *cix_in;
  1329. {
  1330.     int fpos;
  1331.     char *p1, *p2;
  1332.     struct vector *split;
  1333.  
  1334.     for (; *cix_in < wvec->size; (*cix_in)++)
  1335.     {
  1336.     p1 = wvec->item[*cix_in].u.string;
  1337.     if (p1[0] != str[0])
  1338.         continue;
  1339.  
  1340.     if (strcmp(p1, str) == 0) /* str was one word and we found it */
  1341.         return *cix_in;
  1342.  
  1343.     if (!(p2 = strchr(str,' ')))
  1344.         continue;
  1345.  
  1346.     /* If str was multi word we need to make som special checks
  1347.         */
  1348.     if (*cix_in == (wvec->size -1))
  1349.         continue;
  1350.  
  1351.     split = explode_string(str," ");
  1352.  
  1353.     /*
  1354.         wvec->size - *cix_in ==    2: One extra word
  1355.                 3: Two extra words
  1356.         */
  1357.     if (!split || (split->size > (wvec->size - *cix_in))) 
  1358.     {
  1359.         if (split) 
  1360.         free_vector(split);
  1361.         continue;
  1362.     }
  1363.     
  1364.     fpos = *cix_in;
  1365.     for (; (*cix_in-fpos) < split->size; (*cix_in)++)
  1366.     {
  1367.         if (strcmp(split->item[*cix_in-fpos].u.string, 
  1368.                wvec->item[*cix_in].u.string))
  1369.         break;
  1370.     }
  1371.     if ((*cix_in - fpos) == split->size)
  1372.         return fpos;
  1373.  
  1374.     *cix_in = fpos;
  1375.  
  1376.     }
  1377.     return -1;
  1378. }
  1379.  
  1380. /*
  1381.  * Function name:     check_adjectiv
  1382.  * Description:        Checks a word to see if it fits as adjectiv of an
  1383.  *            object.
  1384.  * Arguments:        obix: The index in the global id arrays
  1385.  *            wvec: The command words
  1386.  *            from: #1 cmdword to test
  1387.  *            to:   last cmdword to test
  1388.  * Returns:        True if a match is made.
  1389.  */
  1390. int check_adjectiv(obix, wvec, from, to)
  1391.     int            obix;
  1392.     struct vector    *wvec;
  1393.     int            from;
  1394.     int            to;
  1395. {
  1396.     int il, back, sum, fail;
  1397.     char *adstr;
  1398.     struct vector *ids;
  1399.     int member_string();
  1400.  
  1401.     if (gAdjid_list->item[obix].type == T_POINTER)
  1402.     ids = gAdjid_list->item[obix].u.vec;
  1403.     else
  1404.     ids = 0;
  1405.  
  1406.     for (sum = 0, fail = 0, il = from; il<= to; il++) 
  1407.     {
  1408.     sum += strlen(wvec->item[il].u.string) + 1;
  1409.     if ((member_string(wvec->item[il].u.string, ids) < 0) &&
  1410.         (member_string(wvec->item[il].u.string, gAdjid_list_d) < 0))
  1411.     {
  1412.         fail = 1;
  1413.     }
  1414.     }
  1415.  
  1416.     /* Simple case: all adjs were single word
  1417.     */
  1418.     if (!fail)
  1419.     return 1;    
  1420.  
  1421.     if (from == to)
  1422.     return 0;
  1423.  
  1424.     adstr = xalloc(sum); 
  1425.  
  1426.     for (il = from; il < to;) 
  1427.     {
  1428.     for (back = to; back > il; back--)
  1429.     {
  1430.         strcpy(adstr, "");
  1431.         for (sum = il; sum <= back; sum++)
  1432.         {
  1433.         if (sum > il)
  1434.             strcat(adstr, " ");
  1435.         strcat(adstr, wvec->item[sum].u.string);
  1436.         }
  1437.         if ((member_string(adstr, ids) >= 0) ||
  1438.         (member_string(adstr, gAdjid_list_d) >= 0))
  1439.         {
  1440.         il = back + 1;
  1441.         break;
  1442.         }
  1443.         free(adstr);
  1444.         return 0;
  1445.     }
  1446.     }
  1447.     free(adstr);
  1448.     return 1;
  1449. }
  1450.  
  1451.  
  1452. /*
  1453.  * Function name:     member_string
  1454.  * Description:        Checks if a string is a member of an array.
  1455.  * Arguments:        str: The string to search for
  1456.  *            svec: vector of strings
  1457.  * Returns:        Pos if found else -1.
  1458.  */
  1459. int member_string(str, svec)
  1460.     char        *str;
  1461.     struct vector    *svec;
  1462. {
  1463.     int il;
  1464.  
  1465.     if (!svec)
  1466.     return -1;
  1467.  
  1468.     for (il = 0; il < svec->size; il++)
  1469.     {
  1470.     if (svec->item[il].type != T_STRING)
  1471.         continue;
  1472.  
  1473.     if (strcmp(svec->item[il].u.string, str) == 0)
  1474.         return il;
  1475.     }
  1476.     return -1;
  1477. }
  1478.  
  1479. #ifndef PARSE_FOREIGN
  1480. /*
  1481.  * Function name:     parse_to_plural
  1482.  * Description:        Change a sentence in singular form to a sentence
  1483.  *            in pluralform.
  1484.  * Arguments:        str: The sentence to change
  1485.  * Returns:        Sentence in plural form.
  1486.  */
  1487. char *parse_to_plural(str)
  1488.     char *str;
  1489. {
  1490.     struct vector    *words;
  1491.     struct svalue    stmp;
  1492.     char *sp;
  1493.     int il, changed;
  1494.     char        *parse_one_plural();
  1495.  
  1496.     if (!(strchr(str,' ')))
  1497.     return parse_one_plural(str);
  1498.  
  1499.     words = explode_string(str, " ");
  1500.     
  1501.     for (changed = 0, il = 1; il < words->size; il++) {
  1502.     if ((EQ(words->item[il].u.string,"of")) ||
  1503.         (il+1 == words->size))  {
  1504.         sp = parse_one_plural(words->item[il-1].u.string);
  1505.         if (sp != words->item[il-1].u.string) {
  1506.         stmp.type = T_STRING;
  1507.         stmp.string_type = STRING_MALLOC;
  1508.         stmp.u.string = string_copy(sp);
  1509.         assign_svalue(&words->item[il-1],&stmp);
  1510.         changed = 1;
  1511.         }
  1512.     } 
  1513.     }
  1514.     if (!changed) {
  1515.     free_vector(words);
  1516.     return str;
  1517.     }
  1518.     sp = implode_string(words, " ");
  1519.     free_vector(words);
  1520.     return sp;
  1521. }
  1522.     
  1523.  
  1524. /*
  1525.  * Function name:     parse_one_plural
  1526.  * Description:        Change a noun in singularform to a noun
  1527.  *            in pluralform.
  1528.  * Arguments:        str: The sentence to change
  1529.  * Returns:        Word in plural form.
  1530.  */
  1531. char *parse_one_plural(str)
  1532.     char    *str;
  1533. {
  1534.     char     ch, ch2;
  1535.     int     sl;
  1536.     static char    pbuf[100];   /* Only stupid people finds words > 100 letters */
  1537.     
  1538.     sl=strlen(str) - 1; 
  1539.     if ((sl<2) || (sl>90))
  1540.     return str;
  1541.  
  1542.     ch = str[sl];
  1543.     ch2 = str[sl-1];
  1544.     strcpy(pbuf, str); pbuf[sl] = 0;
  1545.  
  1546.     switch (ch)
  1547.     {
  1548.     case 's':
  1549.     case 'x':
  1550.     case 'h':
  1551.     return strcat(pbuf, "ses");
  1552.     case 'y':
  1553.     return strcat(pbuf, "ies");
  1554.     case 'e':
  1555.     if (ch2 == 'f')
  1556.     {
  1557.         pbuf[sl-1] = 0;
  1558.         return strcat(pbuf, "ves");
  1559.     }
  1560.     }
  1561.     
  1562.     if (EQ(str,"corpse")) return "corpses";
  1563.     if (EQ(str,"tooth")) return "tooth";
  1564.     if (EQ(str,"foot")) return "foot";
  1565.     if (EQ(str,"man")) return "men";
  1566.     if (EQ(str,"woman")) return "women";
  1567.     if (EQ(str,"child")) return "children";
  1568.     if (EQ(str,"sheep")) return "sheep";
  1569.  
  1570.     pbuf[sl] = ch;
  1571.     return strcat(pbuf, "s");
  1572. }
  1573. #endif
  1574.  
  1575. /*
  1576.  
  1577.    End of Parser
  1578.  
  1579. ***************************************************************/
  1580. #endif
  1581.  
  1582. /*
  1583.      ----- describe: This code is obsolete ------
  1584. */
  1585.  
  1586. char *describe_items (arr, func, live)
  1587.     struct svalue *arr;
  1588.     char *func;
  1589.     int live;
  1590. {
  1591.     return "Not supported in 3.0";
  1592. }
  1593.  
  1594. /* process_string
  1595.  *
  1596.  * Description:   Checks a string for the below occurences and replaces:
  1597.  *          Fixes a call to a named function if the value is on the
  1598.  *                form: '@@function[:filename][|arg|arg]@@' Filename is
  1599.  *                optional.
  1600.  *          Note that process_string does not recurse over returned
  1601.  *          replacement values. If a function returns another function
  1602.  *          description, that description will not be replaced.
  1603.  *                Example (added after reading TMI docs :-)
  1604.  *                "You are chased by @@query_name:/obj/monster#123@@ eastward."
  1605.  *                 is replaced by: 
  1606.  *                "You are chased by Orc eastward."
  1607.  *                               (if query_name in monster#123 returns "Orc")
  1608.  *                 
  1609.  *                Note that both object and arguments are optional.
  1610.  * Arguments:     str: A string containing text and function descriptions as
  1611.  *          as described above.
  1612.  * Returns:       String containing the result of all replacements.
  1613.  */
  1614. char *
  1615. process_string(str)
  1616.     char *str;
  1617. {
  1618.     struct vector *vec;
  1619.     struct svalue *ret;
  1620.     struct object *old_cur = current_object;
  1621.     int pr_start, il, changed, ch_last;
  1622.     char *p1, *p2, *p3, *buf, *old_eff_user;
  1623.     char *process_part();
  1624.  
  1625.     if ((!str) || (!(p1=strchr(str,'@'))))
  1626.     return str;
  1627.  
  1628.     /* This means we are called from notify_ in comm1 
  1629.        We must temporary set eff_user to backbone uid for
  1630.        security reasons.
  1631.     */
  1632.  
  1633.     old_eff_user = 0;
  1634.  
  1635.     if (!current_object)
  1636.     {
  1637.     current_object = command_giver;
  1638.     ret = apply_master_ob("get_bb_uid",0);
  1639.     if (!ret || ret->type != T_STRING)
  1640.         return str;
  1641.     if (current_object->eff_user)
  1642.     {
  1643.         old_eff_user = current_object->eff_user->name;
  1644.         current_object->eff_user = add_name(ret->u.string);
  1645.     }
  1646.     }
  1647.     
  1648.     vec = explode_string(str,"@@");
  1649.     if (!vec)
  1650.     return str;
  1651.  
  1652.     pr_start = ((str[0]=='@') && (str[1]=='@'))?0:1;
  1653.  
  1654.     for (ch_last = 0, changed = 0, il = pr_start; il < vec->size; il++) {
  1655.     p1 = strchr(vec->item[il].u.string,' ');
  1656.     if (!p1) {
  1657.         p2 = process_part(vec->item[il].u.string);
  1658.         if (p2 != vec->item[il].u.string) 
  1659.         ch_last = 1;
  1660.     }
  1661.     else
  1662.     {
  1663.         buf = string_copy(vec->item[il].u.string);
  1664.         p1 = strchr(buf,' ');
  1665.         *p1=0;
  1666.         p2 = process_part(buf);
  1667.         *p1=' ';
  1668.         if (p2 != buf)
  1669.         {
  1670.         p3 = xalloc(1+strlen(p1)+strlen(p2));
  1671.         strcpy(p3,p2);
  1672.         strcat(p3,p1);
  1673.         free(p2);
  1674.         p2 = p3;
  1675.         }
  1676.         else
  1677.         p2 = vec->item[il].u.string;
  1678.  
  1679.         free(buf);
  1680.     }
  1681.     if (p2 == vec->item[il].u.string) {
  1682.         if(!ch_last) {              /* get rid of the last snabels */
  1683.         p3 = xalloc(3+strlen(p2));
  1684.         strcpy(p3,"@@"); strcat(p3,p2);
  1685.         p2 = p3;
  1686.         }
  1687.         else
  1688.         ch_last = 0;
  1689.     }
  1690.     else
  1691.         changed = 1;
  1692.  
  1693.     if (p2 != vec->item[il].u.string)
  1694.     {
  1695.         free_svalue(&vec->item[il]);
  1696.         vec->item[il].u.string = string_copy(p2);
  1697.         vec->item[il].string_type = STRING_MALLOC;
  1698.         vec->item[il].type = T_STRING;
  1699.         free(p2);
  1700.     }
  1701.     }
  1702.  
  1703.     if (changed)
  1704.     buf = implode_string(vec, "");
  1705.     else
  1706.     buf = 0;
  1707.  
  1708.     free_vector(vec);
  1709.  
  1710.     if (old_eff_user)
  1711.     {
  1712.     current_object->eff_user = add_name(old_eff_user);
  1713.     }
  1714.  
  1715.     current_object = old_cur;
  1716.  
  1717.     return (buf)?buf:str;
  1718. }
  1719.  
  1720. /*
  1721.  * Process a string holding exactly one 'value by function call'
  1722.  */
  1723. char *process_part(str)
  1724.     char    *str;
  1725. {
  1726.     struct svalue *ret;
  1727.     struct svalue *process_value();
  1728.  
  1729.     if ((strlen(str)<1) || (str[0]<'A') || (str[0]>'z'))
  1730.     return str;
  1731.  
  1732.     ret = process_value(str);
  1733.  
  1734.     if ((ret) && (ret->type == T_STRING))
  1735.     return string_copy(ret->u.string);
  1736.     else
  1737.     return str;
  1738. }
  1739.  
  1740. /*
  1741.  * Function name: process_value
  1742.  * Description:   Fixes a call to a named function on the form:
  1743.  *                'function[:filename][|arg|arg...|arg]' Filename is optional
  1744.  * Arguments:     str: Function as given above
  1745.  * Returns:       The value returned from the function call.
  1746.  */
  1747. struct svalue *process_value(str)
  1748.     char    *str;
  1749. {
  1750.     struct svalue *ret;
  1751.     static struct svalue rval;
  1752.     char *func,*obj,*arg,*narg;
  1753.     int numargs;
  1754.     struct object *ob;
  1755.  
  1756.     rval.type = T_NUMBER;
  1757.     rval.u.number = 0;
  1758.  
  1759.     if ((strlen(str)<1) || (str[0]<'A') || (str[0]>'z'))
  1760.     return &rval;
  1761.  
  1762.     func = string_copy(str);
  1763.  
  1764.     arg = strchr(func,'|'); if (arg) { *arg=0; arg++; }
  1765.     obj = strchr(func,':'); if (obj) { *obj=0; obj++; }
  1766.  
  1767.     /* Find the objectpointer
  1768.     */
  1769.     if (!obj) 
  1770.     ob = current_object;
  1771.     else
  1772.     ob = find_object2(obj);
  1773.  
  1774.     if (!ob)
  1775.     {
  1776.     free(func);
  1777.     return &rval;
  1778.     }
  1779.  
  1780.     /* Push all arguments as strings to the stack
  1781.     */
  1782.     for (numargs = 0; arg; arg=narg)
  1783.     {
  1784.     narg = strchr(arg,'|');
  1785.     if (narg) 
  1786.         *narg = 0; 
  1787.     push_string(arg,STRING_MALLOC); numargs++;
  1788.     if (narg) 
  1789.     {
  1790.         *narg = '|'; narg++;
  1791.     }
  1792.     }
  1793.     
  1794.     /* Apply the function and see if adequate answer is returned
  1795.     */
  1796.     ret = apply(func, ob, numargs);
  1797.  
  1798.     free(func);
  1799.  
  1800.     if (ret)
  1801.     rval = *ret;
  1802.  
  1803.     return &rval;
  1804. }
  1805.   
  1806. /*
  1807.  * Function name: break_string
  1808.  * Description:   Breaks a continous string without newlines into a string
  1809.  *          with newlines inserted at regular intervalls replacing spaces
  1810.  *          Each newline separeted string can be indented with a given
  1811.  *          number of spaces.
  1812.  * Arguments:     str: Original message
  1813.  *          width: The total maximum width of each line.
  1814.  *          indent: (optional) How many spaces to indent with.
  1815.  * Returns:       A string with newline separated strings
  1816.  */
  1817. char *
  1818. break_string(str, width, indent)
  1819.     char     *str;
  1820.     int        width;
  1821.     int        indent;
  1822. {
  1823.     char *fstr, *istr;
  1824.     struct vector *lines;
  1825.  
  1826.     int il, l, nchar, space;
  1827.  
  1828.     fstr = string_copy(str);
  1829.  
  1830.     if (width < 1)
  1831.     width = 1;
  1832.  
  1833.     if (indent > width)
  1834.     indent = 0;
  1835.     
  1836.     for (space = -1, nchar = 0, l = strlen(fstr), il = 0; il < l; il++)
  1837.     {
  1838.     if (fstr[il] == ' ')
  1839.         space = il;
  1840.  
  1841.     if ((il-nchar) > (width + indent) && space >= 0)
  1842.     {
  1843.         fstr[space] = '\n';
  1844.         nchar = space;
  1845.         space = -1;
  1846.     }
  1847.     }
  1848.  
  1849.     if (!indent)
  1850.     return fstr;
  1851.  
  1852.     lines = explode_string(fstr, "\n");
  1853.     if (!lines)
  1854.     return fstr;
  1855.  
  1856.     free(fstr);
  1857.  
  1858.     for (nchar = 0, il = 0; il < lines->size; il++)
  1859.     nchar += indent + strlen(lines->item[il].u.string) + 1;
  1860.     
  1861.     fstr = xalloc(nchar + 1);
  1862.     fstr[0] = 0;
  1863.     istr = xalloc(indent + 1);
  1864.     istr[indent] = 0;
  1865.     for (il = 0; il < indent; il++) 
  1866.     istr[il] = ' ';
  1867.     
  1868.     for (nchar = 0, il = 0; il < lines->size; il++)
  1869.     {
  1870.     strcat(fstr, istr); 
  1871.     strcat(fstr, lines->item[il].u.string);
  1872.     strcat(fstr, "\n");
  1873.     }
  1874.  
  1875.     free(istr);
  1876.     free_vector(lines);
  1877.  
  1878.     return fstr;
  1879.  
  1880. }
  1881.  
  1882.  
  1883. #if 0  
  1884.  
  1885. /*
  1886.  * Function name:   update_actions
  1887.  * Description:     Updates current_objects actions in all living objects
  1888.  */
  1889. void
  1890. update_actions()
  1891. {
  1892.     int             il;
  1893.     object         *objs;
  1894.  
  1895.     if (environment(previous_object()))
  1896.     previous_object()->move(environment(previous_object()), 1);
  1897.  
  1898.     for (objs = all_inventory(previous_object()), il = 0; il < sizeof(objs); il++)
  1899.     if (living(objs[il]))
  1900.         objs[il]->move(previous_object(), 1);
  1901. }
  1902.  
  1903. /*
  1904.  * query_xverb should return the part of the verb that had to be filled in
  1905.  * when an add_action("xxx", "yyyyy", 1) was executed.
  1906.  * Until we get a GD implementation it will simply return query_verb().
  1907.  */
  1908.  nomask string
  1909. query_xverb()
  1910. {
  1911.     return query_verb();
  1912. }
  1913.  
  1914. #endif
  1915.